home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Technotools
/
Technotools (Chestnut CD-ROM)(1993).ISO
/
lang_c
/
ansippv2
/
read.me
< prev
next >
Wrap
Text File
|
1988-09-20
|
23KB
|
460 lines
Thanks for your gratifying response to my article in Computer Language, July
1988, titled "Using Tomorrow's C Standard Today". This disk contains the
latest source and executable code for the ANSI-Conforming C Language
Preprocessor presented there. This is contained in the archive PPV2.ARC.
Don Kneller's NDMAKE
Also included is Don Kneller's NDMAKE utility, which is used to maintain the
preprocessor. If you didn't have a MAKE utility before, you now have one of
the best. If you decide to use it, be sure to support Don's efforts by
becoming a legal user of NDMAKE. This is contained in the archive
NDMAKE43.ARC.
I have included NDMAKE at no charge. Any charge for this disk is for the
preprocessor, not NDMAKE.
Don also markets a commercial version with even more features, called OPUS
Make. It is available from:
OPUS Software
D.G. Kneller and J.F. Thomason
1032 Irving Street
Suite 439
San Francisco, CA 94122
Phil Katz's PKPAK
Both archives may be unpacked using Phil Katz's unsurpassed PKPAK (formerly
PKARC) utility, which is contained in the self-extracting archive PK361.EXE.
Simply running PK361.EXE will unpack Phil's program and documentation into
the current directory. Again, if you find PKPAK useful, please register with
Phil as a legal user.
(Phil and his company PKWARE have recently been the target of a lawsuit by
SEA, with whose ARC.EXE program PKPAK is compatible. You may read the text of
their settlement and decide for yourself, but many people think that Phil was
treated unfairly. By providing us with a fast and useful tool, he exposed
himself to this kind of action, and so we all owe him a great deal.)
I have included PKPAK at no charge. Any charge for this disk is for the
preprocessor, not PKPAK.
Revision Control System
I hope that you will learn from examining this source code. I also hope that
you will make changes to it, so that it better suits your needs. If you do,
you will probably find a revision control system as useful as I do. One of
the most affordable, as well as fast and capable, is TLIB, available from:
Burton Systems Software
P.O. Box 4156
Cary, NC 27519-0156
(919) 469-3068
TLIB allows you to keep track of your revisions as you make them, and also to
merge my changes into your own if I send you a new version. Once you start
using a revision control system, you just can't stop.
The ANSI Draft
Anyone who seriously wants to use the preprocessor should obtain a copy of the
ANSI draft from the address in PP.MAN. Unfortunately, its expensive, but
there's no other way to learn the new features and behavior.
The comments in this source code often refer to sections in the ANSI draft.
Those comments, and the entire preprocessor, are based on the draft dated
January 11, 1988, which is already outdated. If you obtain the ANSI draft
today, you will receive a later revision. The section numbers should be
close. Whether the behavior is close depends on the changes they have made.
The Preprocessor
The following files are included in PPV2.ARC:
ANSI.DAT ANSI "Torture test" examples
ASSERT.H An ANSI assert() macro
ERROR.C Error message function.
ERROR.H Error message function.
MAKE.INI Use with Don Kneller's NDMAKE
MAKEFILE Use with Don Kneller's NDMAKE
MEMORY.C Memory allocation functions.
MEMORY.H Memory allocation functions.
PP.C Standalone preprocessor.
PP.EXE Standalone preprocessor.
PP.H Definitions for PP.LIB.
PP.MAN Brief description of usage
PPCHAR.C Handle trigraph translation.
PPDIRECT.C Preprocessor directives.
PPIFS.C #if and related directives.
PPMACRO.C #define #undef Macro replacement
PPTOK.C Tokenizer.
SYMTAB.C Hashed symbol table functions.
SYMTAB.H Hashed symbol table functions.
VERS2.H A little file used by ANSI.DAT.
Differences From Version 1
The following are a list of differences between Version 1 and Version 2 of the
preprocessor. Any user who has made changes to the Version 1 source code may
contact me to receive a full TLIB revision history of my changes. This would
allow that user to use TLIB to merge my changes with his or her own.
The preprocessor now runs about twice as fast, due to compilation with the
Watcom C Compiler.
The source code itself is closer to ANSI-Conformance, although it still fails
to conform in many places. The primary change is to use prototype function
declarations. Note that the this comment applies to the source code itself,
not to the function of the program. It has always been intended that the
program functions as an ANSI-Conforming C Language Preprocessor. It is
possible for non-conforming C source code to fit that function.
A bug was corrected that produced an incorrect macro replacement or a
diagnostic when any macro invocation contained a parameter that began with a
left parenthesis. For example, the input:
#define str(x) / #x /
#define cat(x, y) | #x #y |
These work OK:
str(test)
cat(left, right)
These work not OK:
str((test))
cat((left), (right))
produces the following output:
These work OK:
/ "test" /
| "leftright" |
These work not OK:
/ "(test" /)
12: Too few macro arguments.
, (right))
A bug was corrected that produced garbage upon certain invalid #include
directives.
#pragma directives are now optionally passed through to the output. Within
passed-through #pragma directives, macros may be replaced, optionally. If
#pragma pass-through is disabled (as by default), #pragma directives are
silently ignored and discarded. This change allows the preprocessor to work
correctly with compilers such as Watcom, to whom #pragma directives are
important. It also allows the preprocessor to correctly handle input that
contains #pragma directives; previously, only the simplest #pragma directives
were discarded without complaint.
The preprocessor now scrupulously frees all dynamically allocated memory.
Previously, memory allocated for the symbol table, and certain other data, was
never freed, because it is used throughout the execution of the preprocessor.
This change is only for my peace of mind. It may be more significant to
others that write programs that call the preprocessor library: a new function,
PPTerminate(), ensures that all memory allocated by the library is freed.
Dynamic memory allocation is now performed via malloc() and free().
Previously, the preprocessor library chose between malloc() and sbrk()
depending on the size of the memory to be allocated. This was important under
the Lattice compiler, whose malloc() and free() are excruciating. There is no
apparent advantage under Watcom, and sbrk() caused other problems.
The NDEBUG macro in ASSERT.H worked backwards. That is, defining NDEBUG
enabled the assert() macro, instead of disabling it as it should.
The __DATE__ and __TIME__ predefined macros are now replaced with the current
date and time, instead of a canned date and time.
Other minor changes to the source code and comments.
The Compiler
This version may be compiled using the Watcom C Compiler version 6.5. I have
also compiled it with various versions of Microsoft C, and it works. More on
the Watcom compiler below.
If you don't use the Watcom compiler, you can probably use your favorite
compiler instead without too much trouble, provided your compiler can handle
prototype function declarations. (This eliminates Lattice.)
WARNING! OPINIONS FOLLOW! GRAIN OF SALT RECOMMENDED!
I give the Watcom compiler my highest possible recommendation. I have met
some of Watcom's designers, and I have dealt with their support people, and I
am very impressed. Support, in particular, is a problem area with both
Lattice and Microsoft, because they are simply too big to be able to afford
enough good people in support. Novell is just as bad.
I don't mean to pick on Lattice, Microsoft, and Novell. There are small
companies with poor support as well. But I make my living as a programmer,
and these are three companies that I deal with extensively, so I am speaking
from experience. Their products are of variable, but generally good quality.
Their support is as good as can be expected. But my expectations of the level
of support from large companies has declined as a result of dealing with them.
I have often wondered why technical support suffers as a software company
grows. It seems to me that if such a company prices its products (and/or its
support) correctly, it should not matter how many units are sold. Because, if
the price of 100 units covers the cost of supporting those 100 units,
shouldn't the cost of a 1,000 units cover the cost of supporting 1,000 units?
10,000? 100,000?
A friend who is more business-oriented than I am points out one possible
reason. If it takes one support person to handle 100 units, there's no
management involved. Ten support people handling 1,000 units might be not
much more complicated. But when one hundred support people are handling
10,000 units, suddenly there looms the spectre of management (gasp!). Now,
phones must be answered (by a less technical person perhaps? sound familiar?),
calls must be tracked in a computer system, someone must perform scheduling,
and so on. Otherwise the technical people would never be able to keep track
of what's going on.
This may be what has happened to Lattice, Microsoft, and Novell. (I won't
even mention IBM.) But I don't think so. I honestly believe (although this
is just speculation, not a statement of fact) that once these large software
companies became large PROFITABLE companies, the business interests took over.
No longer was the priority to produce good programs and support them well.
The priority shifted to those areas that produce revenue for the least
investment. That portion of the price of the product that once covered
support was redirected to advertising, packaging, and new development. And so
technical support is chronically understaffed.
I have heard speculation that, at Microsoft, as soon as a new hire in
technical support shows an uncommon ability to understand the products, he or
she is moved into development, depriving the existing customers of support by
an extremely able person.
And perhaps this is as it should be. After all, whose interests take priority
in any business? The customers who have already paid their money? Or the
investors who deserve a maximal return on their investment? Common business
sense would, in my experience, favor the investors, while giving lip service
to the needs of customers. This is called free enterprise, and it's what
makes our country great.
I'm not being facetious! I honestly believe that the business people should
be able to run any business as they see fit. I won't presume to tell them how
to do their jobs. However, this means that the concerns of business are
fundamentally at odds with my goals as a programmer.
My goals are to write software that has some redeeming value and elegance, and
to support it to the best of my ability. This is why I have distributed this
program in this manner, and why I plug Phil Katz and Don Kneller, above. None
of Don, Phil, or I have a toll-free, 24-hour support hotline, but we don't
charge for one either. Nor do we represent that our technical support is a
big part of the value of our programs. (Lattice, Microsoft, and Novell all
market their support as part of the value of their products.)
What is my favorite software that I use daily? Without question, those
shareware programs like Don Kneller's and Phil Katz's. The price/performance
ratio on these programs is unheard of. And the support turns out to be better
than that of most commercial software vendors.
Running a close second on my list of favorite software is the Watcom compiler.
We are fortunate that there is a compiler vendor that is not yet so large that
it can't support its products. Since Watcom is associated with an educational
institution, perhaps the "suits" won't ruin Watcom as it grows. If you don't
have a C compiler, or if you can afford another, and you don't require
Microsoft C (for Windows or OS/2, for example), get the Watcom compiler.
Third on my list of favorite software is the Mortice Kern Systems ports of
various traditional Unix tools. I have had their AWK language for some time,
and I recently got their "MKS Toolkit". I am considering investing in their
RCS (Revision Control System, somewhat like TLIB), and I lust after their
justifiably expensive SQPS (TROFF-based document preparation). Their prices
are reasonable, and when you call on the telephone, you get somebody who knows
what's what.
More About Watcom C
Watcom C is the first C compiler available for the PC-compatible environment
that even approaches conformance with the draft proposed ANSI standard.
Lattice has told me on the phone that their compiler is, in their words,
"ANSI-Conforming". This indicates how many people still misunderstand what
ANSI Conformance means. Lattice doesn't even fully support prototype function
declarations. Microsoft is more honest. Their documentation states that they
have added ANSI features "in many areas". Fair enough.
But the Watcom compiler is fully ANSI Conforming. And believe me, their
designers know what that means. The new version 6.5 even tracks changes in
the draft proposed standard since their original version 6.0. Until the
standard is approved, compiler vendors will spend much effort tracking the
changes to the draft. I am impressed that Watcom is willing to do so.
Lattice and Microsoft seem to be taking a "wait for approval" approach.
Don't misunderstand me. I am using the term "ANSI Conforming" to mean "ANSI
Conforming, but all programs have bugs". I found one minor area of
non-conformance in version 6.0 of the Watcom C compiler's preprocessor. I
wouldn't say that it rendered the compiler "non-conforming". Rather, I would
say that it was a bug in a "conforming" implementation. I made a bug report,
and Watcom, to their credit, took it as such. I believe it is corrected in
Watcom version 6.5, but I haven't tested it.
(Likewise, some of you will find bugs or areas of non-conformance in my
preprocessor. Please don't bash me for representing the preprocessor as
ANSI-Conforming when it's not. Instead, report these to me as bugs, and I
will do my best to fix them.)
I find the Watcom compiler easier to use than Microsoft's, but that's a matter
of taste.
I believe that Watcom generates better code than Microsoft, but the published
reviews and benchmarks are inconclusive. It's safe to say that they are
neck-and-neck, and so Watcom wins with me because of its other good points.
(Note that I don't even mention Lattice. My preprocessor runs about twice as
fast when compiled with Watcom as with Lattice, with no significant changes to
the code. Gives one pause, don't it?)
Watcom includes a full-screen, source-level debugger that is similar to
Microsoft's CodeView. I haven't yet made a judgement which debugger is
better. Since my job requires me to use CodeView, I suppose I will find out.
Watcom also includes a fast, interactive, integrated (edit/compile/debug)
development environment, similar to Microsoft's Quick-C. I don't use either
one.
Speed of compilation is as unimportant to me as anything I can think of.
Watcom's designers have told me that speed of compilation is one of their top
priorities. In any case, I find both Watcom and Microsoft sufficiently fast.
I speed up Watcom a lot by turning off all optimization until creating a
production version. You can judge compilation speed for yourself.
Watcom has a very interesting set of #pragmas. You can use a #pragma to
direct Watcom to pass parameters in particular machine registers on a
function-by-function basis. This permits mixed-language development without
any interface routines. You can also use a #pragma to cause a function call
to generate in-line code. This is how Watcom replaces calls to strcpy() and
other functions with inline code (optionally). It would even be possible,
with some work, to use #pragmas to allow Watcom-compiled code to call the
Microsoft Windows Toolkit libraries directly. I predict that Watcom's
#pragmas will be put to some very interesting uses.
Watcom includes a Unix-like MAKE facility. I continue to use Don Kneller's
instead because I'm accustomed to it, and because it's closer to Unix's.
Either one is by far preferable to Microsoft's un-Unix-like, verbose,
inflexible MAKE program.
Certainly the inclusion of CodeView- and Quick-C-like features indicate that
Watcom intends their compiler to compete head-to-head with Microsoft C 5.0.
Microsoft lists for $450, and Watcom lists for $295. Watcom has better
support. Watcom generates better code (I believe). Watcom's #pragmas make it
much more flexible than Microsoft. Watcom's MAKE is better.
You decide. I believe that one should choose Microsoft only when Windows or
OS/2 programming is required. I await Watcom's OS/2 version with pleasant
anticipation.
Questions About the Preprocessor
Some users have asked the following good questions.
"How does the -d option work?"
The -d option defines the following (empty) macro. For example:
PP -dMACRONAME file.c
This command preprocesses FILE.C as if it were preceded by the line:
#define MACRONAME
which defines an (empty) macro called MACRONAME. An empty macro is one whose
name is replaced during preprocessing, but whose replacement list is empty.
The typical use of a macro defined by -d is to test if it is defined:
#ifdef MACRONAME
(Note that for this purpose, the replacement list of MACRONAME is
unimportant.) This allows the PP command line to change the behavior of a
compilation, without requiring changes to the file.
The preprocessor source code uses -d as follows:
pp -dNDEBUG ppmacro.c
The macro NDEBUG, if defined, disables the assert() macro. If NDEBUG is not
defined, assert() is armed to test for internal errors (see ANSI). In this
way, I can turn assert() on and off without making changes to my source files.
"When I redirect the output, why do errors still go to the screen?"
The preprocessor uses the Unix philosophy of how commands should work.
Commands should take their input from "standard input", and produce their
output on "standard output". Standard input and output are the keyboard and
screen, by default, but either or both may be redirected on the command line
to a file. Or, standard output may be fed directly into another program, as
if through a "pipe". DOS supports a similar capability.
In this way, several Unix-style commands may be connected, as if to form a
"pipeline". Each performs its transformation on the input to the pipeline,
and the result of all transformations is available at the output of the
pipeline.
For example, in the following command:
PP <file.c >file.pp
the preprocessor is the whole pipeline, FILE.C is the input, and the
transformed, preprocessed output is redirected to FILE.PP. When this is done,
why do errors still appear on the screen?
To go back to Unix philosophy, programs further down the pipeline (that is,
those who receive the preprocessed output) are only interested in the
transformed, preprocessed data. On the other hand, the human user, looking at
the screen, is only interested in errors, not necessarily each and every
transformed line that is going down the pipeline. Therefore, Unix (and DOS)
provide another type of output, "standard error output", which is not
redirected, even if standard output is redirected.
Thus, if a program writes its transformed data to standard output, and its
diagnostic output to standard error, everybody gets to see the part of the
output that they're interested in. The human user gets to see diagnostics,
because standard error is not redirected. Programs further down the pipeline
get to see the transformed data, because standard output is piped to them.
If the user does not redirect standard output, then both the transformed data
and the diagnostics appear intermingled on the screen, as expected.
"Why not pass invalid macro redefinitions through to the output?"
What the preprocessor does with invalid input is somewhat arbitrary.
Typically, it throws all or part of it away. Preprocessor directives,
including macro definitions, are never passed through to the output, whether
valid or not (with the optional except of #pragma directives). This is the
whole purpose of the preprocessor, to execute the preprocessor directives, and
pass the resulting raw token stream to the output. Even the #line directives
which may be optionally included in the output do not necessarily relate to
the #line directives in the input.
"Why does ANSI.DAT cause errors?"
ANSI.DAT contains a number of examples of macro definition and replacement
that appear in the draft proposed standard. Some of these examples are
intended to DEMONSTRATE invalid stuff. As such, the preprocessor correctly
diagnoses these errors.
Good Luck!
If you have more questions, or suggestions, please write to me. I'll try to
be as responsive as I can.
Please pass the preprocessor on to interested friends and colleagues.
Encourage them to send me $15 to receive the next version, as I have
encouraged you to support the folks mentioned above. We're all in this
together.
Don't use the preprocessor, or any part of it, in a commercial product,
without first making arrangements with me. Please do use it in programs that
you distribute freely, without charge.
Steven Bruce Williams
P.O. Box 8458
Bridgeport, CT 06605-0997